package org.tinycloud.tinyjob.config;

import org.tinycloud.tinyjob.client.constant.CommonCode;
import org.tinycloud.tinyjob.client.exception.BusinessException;
import org.tinycloud.tinyjob.model.ApiResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.converter.HttpMessageConversionException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;

import java.util.List;
import java.util.Set;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;

/**
 * <p>
 *     全局异常处理
 * </p>
 *
 * @author liuxingyu01
 * @since 2023-05-30 13:28
 */
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 捕获404异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(NoHandlerFoundException.class)
    public ApiResult<?> handle404Error(Throwable e) {
        return buildResponseEntity(CommonCode.RESOURCE_NOT_FOUND.getCode(), CommonCode.RESOURCE_NOT_FOUND.getDesc());
    }


    /**
     * 参数校验异常
     *
     * @param e
     * @return
     */
    @ExceptionHandler(BindException.class)
    public ApiResult<?> paramBind(BindException e) {
        // 对校验结果统一输出
        List<FieldError> fieldErrors = e.getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError error : fieldErrors) {
            sb.append(error.getField()).append("：").append(error.getDefaultMessage()).append(", ");
        }
        String message = sb.toString();
        if (message != null && message.length() > 2) {
            message = message.substring(0, message.length() - 2);
        }
        return buildResponseEntity(CommonCode.PARAM_ERROR.getCode(), message);
    }

    /**
     * 参数校验异常1
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ApiResult<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        // 对校验结果统一输出
        List<FieldError> fieldErrors = e.getBindingResult().getFieldErrors();
        StringBuilder sb = new StringBuilder();
        for (FieldError error : fieldErrors) {
            sb.append(error.getField()).append("：").append(error.getDefaultMessage()).append(", ");
        }
        String message = sb.toString();
        if (message != null && message.length() > 2) {
            message = message.substring(0, message.length() - 2);
        }
        return buildResponseEntity(CommonCode.PARAM_ERROR.getCode(), message);
    }


    /**
     * 参数校验异常3
     * 专用于List直接作为入参时的直接校验和其子内容的嵌套校验  ( @RequestBody @Valid @NotEmpty(message = "列表不能为空") List<User> request )
     * @param e ConstraintViolationException
     */
    @ExceptionHandler(ConstraintViolationException.class)
    public ApiResult<?> handleConstraintViolation(ConstraintViolationException e) {
        // 获取所有校验失败的约束
        StringBuilder errorMsg = new StringBuilder();

        Set<ConstraintViolation<?>> violations = e.getConstraintViolations();
        for (ConstraintViolation<?> violation : violations) {
            // 获取校验失败的字段路径（如"batchAdd.request[0].username"）
            String field = violation.getPropertyPath().toString();
            String message = violation.getMessage();
            errorMsg.append(field).append("：").append(message).append(", ");
        }
        // 去除最后多余的", "
        if (errorMsg.length() > 2) {
            errorMsg = new StringBuilder(errorMsg.substring(0, errorMsg.length() - 2));
        }
        return buildResponseEntity(CommonCode.PARAM_ERROR.getCode(), errorMsg.toString());
    }


    @ExceptionHandler(BusinessException.class)
    public ApiResult<?> handleBusinessException(BusinessException e) {
        return buildResponseEntity(e.getCode(), e.getMessage());
    }

    @ExceptionHandler(Exception.class)
    public ApiResult<?> exception(Throwable throwable) {
        log.error("系统处理异常：", throwable);
        // 参数格式转换异常
        if (throwable instanceof IllegalArgumentException
                || throwable instanceof HttpMessageConversionException
                || throwable instanceof MethodArgumentTypeMismatchException) {
            return buildResponseEntity(CommonCode.PARAM_ERROR.getCode(), CommonCode.PARAM_ERROR.getDesc());
        }
        if (throwable instanceof HttpRequestMethodNotSupportedException) {
            return buildResponseEntity(CommonCode.RESOURCE_METHOD_NOT_SUPPORT.getCode(), CommonCode.RESOURCE_METHOD_NOT_SUPPORT.getDesc());
        }
        return buildResponseEntity(CommonCode.UNKNOWN_ERROR.getCode(), CommonCode.UNKNOWN_ERROR.getDesc());
    }

    private static ApiResult<?> buildResponseEntity(String code, String msg) {
        return ApiResult.fail(code, msg);
    }
}
